//
//  Execute.c
//  Wood
//
//  Created by Wayne on 9/10/14.
//  Copyright (c) 2014 Wayne. All rights reserved.
//

#include <stdio.h>
#include "Arch.h"
#include "Functions.h"

static StatementResult executeStatement(Frame *frame, Statement *statement);

static void defineWoodFunction(Frame *frame, char *identifier, ParameterList *parameterList, Block *block) {
    if (searchFunctionDefinitionFromFrame(frame, identifier)) {
        /* TODO: runtime error - function multiper definition */
    }
    addFunctionDefinitionToFrame(frame, identifier, parameterList, block);
}

static StatementResult executeExpressionStatement(Frame *frame, Statement *statement) {
    StatementResult result;
    Value v;
    result.type = WdNormalStatementResult;
    v = evalExpression(frame, statement->u.expressionStatement);
    return result;
}

static StatementResult executeReturnStatement(Frame *frame, Statement *statement) {
    StatementResult result;
    result.type = WdReturnStatementResult;
    if (statement->u.returnStatement->returnExpression != NULL) {
        result.u.returnValue = evalExpression(frame, statement->u.returnStatement->returnExpression);
    } else {
        result.u.returnValue.type = WdNullValue;
    }
    return result;
}

static StatementResult executeFunctionDefinitionStatement(Frame *frame, Statement *statement) {
    StatementResult result;
    result.type = WdNormalStatementResult;
    defineWoodFunction(frame, statement->u.functionDefinitionStatement->identifier, statement->u.functionDefinitionStatement->parameter, statement->u.functionDefinitionStatement->block);
    return result;
}

static StatementResult executeStatement(Frame *frame, Statement *statement) {
    StatementResult result;
    result.type = WdNormalStatementResult;
    switch (statement->type) {
        case WdExpressionStatement:
            result = executeExpressionStatement(frame, statement);
            break;
        case WdReturnStatement:
            result = executeReturnStatement(frame, statement);
            break;
        case WdFunctionDefinitionStatement:
            result = executeFunctionDefinitionStatement(frame, statement);
            break;
        default:
            /* TODO: runtime error - bad statement */
            ;
    }
    return result;
}

StatementResult executeStatementList(Frame *frame, StatementList *statementList) {
    StatementList *statement;
    StatementResult result;
    result.type = WdNormalStatementResult;
    for (statement = statementList; statement != NULL; statement = statement->next) {
        result = executeStatement(frame, statement->statement);
        if (result.type != WdNormalStatementResult) {
            goto END;
        }
    }
END:
    return result;
}